﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace NGIS.Data.Schema
{
    public class UdxDatasetSchema : UdxNodeSchema
    {
        public UdxDatasetSchema(UdxNodeSchema pParent, string pName)
            : base(pParent, pName, null)
        {
            mDescription = new UdxNodeDescription(ESchemaNodeType.EDTKT_NODE, "");
        }

        /////////////////////////////////////////////////////////////////////////////////////
        public string getName()
        {
            return base.getName();
        }

        public UdxNodeDescription getDescription()
        {
            return base.getDescription();
        }

        public int getChildNodeCount()
        {
            return base.getChildNodeCount();
        }

        public UdxNodeSchema getChildNode(int idx)
        {
            return base.getChildNode(idx);
        }

        public UdxNodeSchema addChildNode(string pName, UdxNodeDescription pDescription)
        {
            return base.addChildNode(pName, pDescription);
        }

        public UdxNodeSchema addChildNode(string pName, ESchemaNodeType pNodeType, string pNodeInfo = "")
        {
            return base.addChildNode(pName, pNodeType, pNodeInfo);
        }

        public bool removeChildNode(UdxNodeSchema pNode)
        {
            return base.removeChildNode(pNode);
        }

        public bool removeChildNode(int idx)
        {
            return base.removeChildNode(idx);
        }

        /////////////////////////////////////////////////////////////////////////////////////
        public bool LoadFromXmlFile(string fileName)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(fileName);
            XmlElement rootEle = doc.DocumentElement;
            rootEle = (XmlElement)(rootEle.ChildNodes[0]);
            int count = rootEle.ChildNodes.Count;
            for (int i = 0; i < count; i++)
            {
                ParseXDO((UdxNodeSchema)this, (XmlElement)rootEle.ChildNodes[i]);
            }

            XmlElement semanticEle = (XmlElement)(rootEle.ChildNodes[1]);
            if (semanticEle != null)
            {
                count = semanticEle.ChildNodes.Count;
                for (int i = 0; i < count; i++)
                {
                    XmlElement childEle = (XmlElement)semanticEle.ChildNodes[i];
                    string ele_name = childEle.Name;
                    if (ele_name == "Concepts")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifyConceptTag(resourceId);
                        }
                    }
                    else if (ele_name == "SpatialRefs")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifySpatialReferenceTag(resourceId);
                        }
                    }
                    else if (ele_name == "Units")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifyUnitTag(resourceId);
                        }
                    }
                    else if (ele_name == "DataTemplates")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifyDataTemplateTag(resourceId);
                        }
                    }
                }
            }

            return true;
        }

        public bool FormatToXmlFile(string fileName)
        {
            XmlDocument doc = new XmlDocument();
            XmlElement element = doc.CreateElement("UdxDeclaration");
            doc.AppendChild(element);
            XmlElement rootEle = doc.CreateElement("UdxNode");
            element.AppendChild(rootEle);

            XmlElement semanticNode = doc.CreateElement("SemanticAttachment");
            element.AppendChild(semanticNode);
            XmlElement conceptsEle = doc.CreateElement("Concepts");
            semanticNode.AppendChild(conceptsEle);
            XmlElement spatialRefsEle = doc.CreateElement("SpatialRefs");
            semanticNode.AppendChild(spatialRefsEle);
            XmlElement unitsEle = doc.CreateElement("Units");
            semanticNode.AppendChild(unitsEle);
            XmlElement dataTemplatesEle = doc.CreateElement("DataTemplates");
            semanticNode.AppendChild(dataTemplatesEle);

            int count = this.getChildNodeCount();
            for (int iNode = 0; iNode < count; iNode++)
            {
                UdxNodeSchema tempNode = this.getChildNode(iNode);
                FormatXDO(tempNode, rootEle, element);
            }

            if (conceptsEle.ChildNodes.Count==0 &&
                spatialRefsEle.ChildNodes.Count == 0 &&
                unitsEle.ChildNodes.Count == 0 &&
                dataTemplatesEle.ChildNodes.Count == 0)
            {
                doc.DocumentElement.RemoveChild(semanticNode);
            }

            doc.Save(fileName);
            return true;
        }

        public bool LoadFromXmlStream(string xmlStr)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlStr);
            XmlElement rootEle = doc.DocumentElement;
            rootEle = (XmlElement)(rootEle.ChildNodes[0]);
            int count = rootEle.ChildNodes.Count;
            for (int i = 0; i < count; i++)
            {
                ParseXDO((UdxNodeSchema)this, (XmlElement)rootEle.ChildNodes[i]);
            }

            XmlElement semanticEle = (XmlElement)(rootEle.ChildNodes[1]);
            if (semanticEle != null)
            {
                count = semanticEle.ChildNodes.Count;
                for (int i = 0; i < count; i++)
                {
                    XmlElement childEle = (XmlElement)semanticEle.ChildNodes[i];
                    string ele_name = childEle.Name;
                    if (ele_name == "Concepts")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifyConceptTag(resourceId);
                        }
                    }
                    else if (ele_name == "SpatialRefs")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifySpatialReferenceTag(resourceId);
                        }
                    }
                    else if (ele_name == "Units")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifyUnitTag(resourceId);
                        }
                    }
                    else if (ele_name == "DataTemplates")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifyDataTemplateTag(resourceId);
                        }
                    }
                }
            }

            return true;
        }

        public bool FormatToXmlStream(ref string xmlStr)
        {
            XmlDocument doc = new XmlDocument();
            XmlElement element = doc.CreateElement("UdxDeclaration");
            doc.AppendChild(element);
            XmlElement rootEle = doc.CreateElement("UdxNode");
            element.AppendChild(rootEle);

            XmlElement semanticNode = doc.CreateElement("SemanticAttachment");
            element.AppendChild(semanticNode);
            XmlElement conceptsEle = doc.CreateElement("Concepts");
            semanticNode.AppendChild(conceptsEle);
            XmlElement spatialRefsEle = doc.CreateElement("SpatialRefs");
            semanticNode.AppendChild(spatialRefsEle);
            XmlElement unitsEle = doc.CreateElement("Units");
            semanticNode.AppendChild(unitsEle);
            XmlElement dataTemplatesEle = doc.CreateElement("DataTemplates");
            semanticNode.AppendChild(dataTemplatesEle);

            int count = this.getChildNodeCount();
            for (int iNode = 0; iNode < count; iNode++)
            {
                UdxNodeSchema tempNode = this.getChildNode(iNode);
                FormatXDO(tempNode, rootEle, element);
            }

            if (conceptsEle.ChildNodes.Count == 0 &&
                spatialRefsEle.ChildNodes.Count == 0 &&
                unitsEle.ChildNodes.Count == 0 &&
                dataTemplatesEle.ChildNodes.Count == 0)
            {
                doc.DocumentElement.RemoveChild(semanticNode);
            }

            xmlStr = doc.InnerXml;
            return true;
        }

        public bool LoadFromXmlElement(XmlElement rootEle)
        {
            rootEle = (XmlElement)(rootEle.ChildNodes[0]);
            int count = rootEle.ChildNodes.Count;
            for (int i = 0; i < count; i++)
            {
                ParseXDO((UdxNodeSchema)this, (XmlElement)rootEle.ChildNodes[i]);
            }

            XmlElement semanticEle = (XmlElement)(rootEle.ChildNodes[1]);
            if (semanticEle != null)
            {
                count = semanticEle.ChildNodes.Count;
                for (int i = 0; i < count; i++)
                {
                    XmlElement childEle = (XmlElement)semanticEle.ChildNodes[i];
                    string ele_name = childEle.Name;
                    if (ele_name == "Concepts")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifyConceptTag(resourceId);
                        }
                    }
                    else if (ele_name == "SpatialRefs")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifySpatialReferenceTag(resourceId);
                        }
                    }
                    else if (ele_name == "Units")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifyUnitTag(resourceId);
                        }
                    }
                    else if (ele_name == "DataTemplates")
                    {
                        foreach (var item in childEle.ChildNodes)
                        {
                            XmlElement infoEle = (XmlElement)item;
                            string nodeId = infoEle.GetAttribute("nodeId");
                            string resourceId = infoEle.GetAttribute("conceptId");
                            UdxNodeSchema dataNode = getNodeWithId(nodeId);
                            dataNode.getDescription().modifyDataTemplateTag(resourceId);
                        }
                    }
                }
            }

            return true;
        }

        public bool FormatToXmlElement(ref XmlElement xmlElement)
        {
            XmlDocument doc = xmlElement.OwnerDocument;
            XmlElement element = doc.CreateElement("UdxDeclaration");
            xmlElement.AppendChild(element);
            XmlElement rootEle = doc.CreateElement("UdxNode");
            element.AppendChild(rootEle);

            XmlElement semanticNode = doc.CreateElement("SemanticAttachment");
            element.AppendChild(semanticNode);
            XmlElement conceptsEle = doc.CreateElement("Concepts");
            semanticNode.AppendChild(conceptsEle);
            XmlElement spatialRefsEle = doc.CreateElement("SpatialRefs");
            semanticNode.AppendChild(spatialRefsEle);
            XmlElement unitsEle = doc.CreateElement("Units");
            semanticNode.AppendChild(unitsEle);
            XmlElement dataTemplatesEle = doc.CreateElement("DataTemplates");
            semanticNode.AppendChild(dataTemplatesEle);

            int count = this.getChildNodeCount();
            for (int iNode = 0; iNode < count; iNode++)
            {
                UdxNodeSchema tempNode = this.getChildNode(iNode);
                FormatXDO(tempNode, rootEle, element);
            }

            if (conceptsEle.ChildNodes.Count == 0 &&
                spatialRefsEle.ChildNodes.Count == 0 &&
                unitsEle.ChildNodes.Count == 0 &&
                dataTemplatesEle.ChildNodes.Count == 0)
            {
                element.RemoveChild(semanticNode);
            }

            return true;
        }

        /////////////////////////////////////////////////////////////////////////////////
        private void ParseXDO(UdxNodeSchema containerNode, XmlElement element)
        {
            string name = element.GetAttribute("name");
            string description = element.GetAttribute("description");
            string typeStr = element.GetAttribute("type");
            ESchemaNodeType kernelType;
            if (typeStr == "")
            {
                kernelType = ESchemaNodeType.EDTKT_NODE;
                
				UdxNodeSchema node = containerNode.addChildNode(name, kernelType, description);
                string resourceId = element.GetAttribute("externalId");
				node.getDescription().modifyDataTemplateTag(resourceId);
            }
            else
            {
                kernelType = UdxNodeDescription.String2SchemaNodeType(typeStr);

                UdxNodeSchema node = containerNode.addChildNode(name, kernelType, description);

                if (kernelType == ESchemaNodeType.EDTKT_NODE ||
                    kernelType == ESchemaNodeType.EDTKT_LIST ||
                    kernelType == ESchemaNodeType.EDTKT_MAP ||
                    kernelType == ESchemaNodeType.EDTKT_TABLE)
                {
                    int count = element.ChildNodes.Count;
                    for (int i = 0; i < count; i++)
                    {
                        ParseXDO(node, (XmlElement)(element.ChildNodes[i]));
                    }
                }
            }
        }

        private void FormatXDO(UdxNodeSchema pNode, XmlElement element, XmlElement rootElement)
        {
            ESchemaNodeType kernelType = pNode.getDescription().getKernelType();
            string name = pNode.getName();
            string nodeType = UdxNodeDescription.SchemaNodeType2String(kernelType);
            string nodeInfo = pNode.getDescription().getNodeDescription();
            XmlDocument doc = element.OwnerDocument;
            XmlElement childEle = doc.CreateElement("UdxNode");
            element.AppendChild(childEle);
            childEle.SetAttribute("name", name);
            childEle.SetAttribute("type", nodeType);
            childEle.SetAttribute("description", nodeInfo);

            XmlElement semanticNode = (XmlElement)rootElement.ChildNodes[1];
            XmlElement conceptsEle = null;
            XmlElement spatialRefsEle = null;
            XmlElement unitsEle = null;
            XmlElement dataTemplatesEle = null;
            if (semanticNode == null)
            {
                semanticNode = doc.CreateElement("SemanticAttachment");
                rootElement.AppendChild(semanticNode);

                conceptsEle = doc.CreateElement("Concepts");
                semanticNode.AppendChild(conceptsEle);
                spatialRefsEle = doc.CreateElement("SpatialRefs");
                semanticNode.AppendChild(spatialRefsEle);
                unitsEle = doc.CreateElement("Units");
                semanticNode.AppendChild(unitsEle);
                dataTemplatesEle = doc.CreateElement("DataTemplates");
                semanticNode.AppendChild(dataTemplatesEle);
            }
            else
            {
                conceptsEle = (XmlElement)semanticNode.ChildNodes[0];
                spatialRefsEle = (XmlElement)semanticNode.ChildNodes[1];
                unitsEle = (XmlElement)semanticNode.ChildNodes[2];
                dataTemplatesEle = (XmlElement)semanticNode.ChildNodes[3];
            }

            string conceptInfo = pNode.getDescription().getConceptTag();
            string spatialRefInfo = pNode.getDescription().getSpatialReferencefTag();
            string unitInfo = pNode.getDescription().getUnitTag();
            string dataTemplateInfo = pNode.getDescription().getDataTemplateTag();
            if (conceptInfo != "")
            {
                XmlElement s_node = doc.CreateElement("Concept");
                conceptsEle.AppendChild(s_node);
                s_node.SetAttribute("nodeId", name);
                s_node.SetAttribute("conceptId", conceptInfo);
            }
            if (spatialRefInfo != "")
            {
                XmlElement s_node = doc.CreateElement("SpatialRef");
                spatialRefsEle.AppendChild(s_node);
                s_node.SetAttribute("nodeId", name);
                s_node.SetAttribute("spatialRefId", spatialRefInfo);
            }
            if (unitInfo != "")
            {
                XmlElement s_node = doc.CreateElement("Unit");
                unitsEle.AppendChild(s_node);
                s_node.SetAttribute("nodeId", name);
                s_node.SetAttribute("unitId", unitInfo);
            }
            if (dataTemplateInfo != "")
            {
                XmlElement s_node = doc.CreateElement("DataTemplate");
                dataTemplatesEle.AppendChild(s_node);
                s_node.SetAttribute("nodeId", name);
                s_node.SetAttribute("dataTemplateId", dataTemplateInfo);
            }

            if (kernelType == ESchemaNodeType.EDTKT_NODE ||
                kernelType == ESchemaNodeType.EDTKT_LIST ||
                kernelType == ESchemaNodeType.EDTKT_MAP ||
                kernelType == ESchemaNodeType.EDTKT_TABLE)
            {
                int count = pNode.getChildNodeCount();
                for (int iNode = 0; iNode < count; iNode++)
                {
                    UdxNodeSchema tempNode = pNode.getChildNode(iNode);
                    FormatXDO(tempNode, childEle, rootElement);
                }
            }
        }

        private UdxNodeSchema getNodeWithId(string pNodeId)
        {
            int count = getChildNodeCount();
            for (int iNode = 0; iNode < count; iNode++)
            {
                UdxNodeSchema tempNode = getChildNode(iNode);
                string temp_name = tempNode.getName();
                if (temp_name == pNodeId)
                {
                    return tempNode;
                }
            }
            return null;
        }

    };
}
